﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StatusBarPanelImpl.h"
#include "DebugMessage.h"
#include "FindByIdPredicate.h"
#include "GbmpNew.h"
#include "IControl.h"
#include "ILineEditDefinition.h"
#include "IComboBoxDefinition.h"
#include "ICommandButtonMenuDefinition.h"
#include "ICommandButtonDefinition.h"
#include "ICheckBoxGroupDefinition.h"
#include "IRadioButtonGroupDefinition.h"
#include "ILabelDefinition.h"
#include "IProgressBarDefinition.h"
#include "IControlDefinitionLibrary.h"
#include "IControlDefinitionLibraryEventArgs.h"
#include "IControlDefinitionLibraryEvent.h"
#include <QCheckBox>
#include <QHBoxLayout>
#include <QButtonGroup>

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

namespace gcmp
{

StatusBarPanelImpl::StatusBarPanelImpl(const std::wstring& name, int minWidth, int stretch)
    : m_name(name)
    , m_minWidth(minWidth)
    , m_stretch(stretch)
{
    m_pHBoxLayout = NEW_AS_QT_CHILD(QHBoxLayout, this);
    m_pHBoxLayout->setContentsMargins(1, 0, 1, 0);
    setLayout(m_pHBoxLayout);
    setMinimumWidth(minWidth);
    IControlDefinitionLibrary* library = IControlDefinitionLibrary::Get();
    if (library && library->GetEvent())
    {
        library->GetEvent()->Add(this);
    }
}

StatusBarPanelImpl::~StatusBarPanelImpl()
{

}

std::wstring StatusBarPanelImpl::GetPanelId() const
{
    return m_name;
}

IControl* StatusBarPanelImpl::AddButton(OwnerPtr<ICommandButtonDefinition> pButtonDefinition)
{
    return AddControl<ICommandButtonDefinition>(TransferOwnership(pButtonDefinition));
}

IControl* StatusBarPanelImpl::AddLineEdit(OwnerPtr<ILineEditDefinition> pLineEditDefinition)
{
    return AddControl<ILineEditDefinition>(TransferOwnership(pLineEditDefinition));
}

IControl* StatusBarPanelImpl::AddComboBox(OwnerPtr<IComboBoxDefinition> pComboBoxDefinition)
{
    return AddControl<IComboBoxDefinition>(TransferOwnership(pComboBoxDefinition));
}

IControl* StatusBarPanelImpl::AddButtonMenu(OwnerPtr<ICommandButtonMenuDefinition> pButtonMenuDefinition)
{
    return AddControl<ICommandButtonMenuDefinition>(TransferOwnership(pButtonMenuDefinition));
}

IControl* StatusBarPanelImpl::AddCheckBoxGroup(OwnerPtr<ICheckBoxGroupDefinition> pCheckBoxGroupDefinition)
{
    return AddControlGroup<ICheckBoxGroupDefinition>(TransferOwnership(pCheckBoxGroupDefinition));
}

IControl* StatusBarPanelImpl::AddRadioButtonGroup(OwnerPtr<IRadioButtonGroupDefinition> pRadioButtonGroupDefinition)
{
    return AddControlGroup<IRadioButtonGroupDefinition>(TransferOwnership(pRadioButtonGroupDefinition));
}

IControl* StatusBarPanelImpl::AddLabel(OwnerPtr<ILabelDefinition> pLabelDefinition)
{
    return AddControl<ILabelDefinition>(TransferOwnership(pLabelDefinition));
}

IControl* StatusBarPanelImpl::AddProgressBar(OwnerPtr<IProgressBarDefinition> pProgressBarDefinition)
{
    return AddControl<IProgressBarDefinition>(TransferOwnership(pProgressBarDefinition));
}

IControl* StatusBarPanelImpl::InsertButton(const std::wstring& followingControlDefinitionId, OwnerPtr<ICommandButtonDefinition> pButtonDefinition)
{
    return InsertControl<ICommandButtonDefinition>(followingControlDefinitionId, TransferOwnership(pButtonDefinition));
}

IControl* StatusBarPanelImpl::InsertLineEdit(const std::wstring& followingControlDefinitionId, OwnerPtr<ILineEditDefinition> pLineEditDefinition)
{
    return InsertControl<ILineEditDefinition>(followingControlDefinitionId, TransferOwnership(pLineEditDefinition));
}

IControl* StatusBarPanelImpl::InsertComboBox(const std::wstring& followingControlDefinitionId, OwnerPtr<IComboBoxDefinition> pComboBoxDefinition)
{
    return InsertControl<IComboBoxDefinition>(followingControlDefinitionId, TransferOwnership(pComboBoxDefinition));
}

IControl* StatusBarPanelImpl::InsertButtonMenu(const std::wstring& followingControlDefinitionId, OwnerPtr<ICommandButtonMenuDefinition> pCommandButtonMenuDefinition)
{
    return InsertControl<ICommandButtonMenuDefinition>(followingControlDefinitionId, TransferOwnership(pCommandButtonMenuDefinition));
}

IControl* StatusBarPanelImpl::InsertCheckBoxGroup(const std::wstring& followingControlDefinitionId, OwnerPtr<ICheckBoxGroupDefinition> pCheckBoxGroupDefinition)
{
    return InsertControlGroup<ICheckBoxGroupDefinition>(followingControlDefinitionId, TransferOwnership(pCheckBoxGroupDefinition));
}

IControl* StatusBarPanelImpl::InsertRadioButtonGroup(const std::wstring& followingControlDefinitionId, OwnerPtr<IRadioButtonGroupDefinition> pRadioButtonGroupDefinition)
{
    return InsertControlGroup<IRadioButtonGroupDefinition>(followingControlDefinitionId, TransferOwnership(pRadioButtonGroupDefinition));
}

IControl* StatusBarPanelImpl::InsertLabel(const std::wstring& followingControlDefinitionId, OwnerPtr<ILabelDefinition> pLabelDefinition)
{
    return InsertControl<ILabelDefinition>(followingControlDefinitionId, TransferOwnership(pLabelDefinition));
}

IControl* StatusBarPanelImpl::InsertProgressBar(const std::wstring& followingControlDefinitionId, OwnerPtr<IProgressBarDefinition> pProgressBarDefinition)
{
    return InsertControl<IProgressBarDefinition>(followingControlDefinitionId, TransferOwnership(pProgressBarDefinition));
}

IControl* StatusBarPanelImpl::GetControl(const std::wstring& id) const
{
    auto search = std::find_if(m_controls.begin(), m_controls.end(), FindControlPtrByIdPredicate<OwnerPtr<IControl>>(id));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(search != m_controls.end(), L"没找到名字：" + id,L"GDMPLab",L"2024-03-30");
    return const_cast<IControl*>(search->get());
}

std::vector<IControl*> StatusBarPanelImpl::GetAllControls() const
{
    std::vector<IControl*> res;
    for (auto& item : m_controls)
    {
        res.push_back(const_cast<IControl*>(item.get()));
    }
    return res;
}

bool StatusBarPanelImpl::DeleteControl(const std::wstring& id)
{
    auto search = std::find_if(m_controls.begin(), m_controls.end(), FindControlPtrByIdPredicate<OwnerPtr<IControl>>(id));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(search != m_controls.end(), L"没找到要删除的名字：" + id,L"GDMPLab",L"2024-03-30");

    if (QButtonGroup* pButtonGroup = dynamic_cast<QButtonGroup*>(search->get()))
    {
        QList<QAbstractButton*> buttons = pButtonGroup->buttons();
        for (auto button : buttons)
        {
            DBG_WARN_AND_CONTINUE_UNLESS(button, L"button是空指针",L"GDMPLab",L"2024-03-30");
            button->deleteLater();
        }
    }
    m_controls.erase(search);
    return true;
}

void StatusBarPanelImpl::DeleteAllControls()
{
    for (auto& pControl : m_controls)
    {
        if (QButtonGroup* pButtonGroup = dynamic_cast<QButtonGroup*>(pControl.get()))
        {
            QList<QAbstractButton*> buttons = pButtonGroup->buttons();
            for (auto button : buttons)
            {
                DBG_WARN_AND_CONTINUE_UNLESS(button, L"button是空指针",L"GDMPLab",L"2024-03-30");
                button->deleteLater();
            }
        }              
    }
    m_controls.clear();
}

void StatusBarPanelImpl::On(IControlDefinitionLibraryEventArgs* pArgs)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pArgs, L"pArgs为空",L"GDMPLab",L"2024-03-30");
    std::wstring deleteId = pArgs->GetDeleteControlDefinitionId();
    auto search = std::find_if(m_controls.begin(), m_controls.end(), FindControlPtrByIdPredicate<OwnerPtr<IControl>>(deleteId));
    if (search == m_controls.end())
        return;
    DBG_WARN_AND_RETURN_VOID_UNLESS(*search, L"IControl为空",L"GDMPLab",L"2024-03-30");
    IControlDefinition*  pControlDef = (*search)->GetControlDefinition();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pControlDef, L"pControlDef为空",L"GDMPLab",L"2024-03-30");
    if (pControlDef->GetType() != pArgs->GetDeleteControlDefinitionType())  //类型不相同，
        return;

    if (IControlDefinition::IsReference(pControlDef))
    {
        DeleteControl(deleteId);
    }
}

void StatusBarPanelImpl::UpdateControlStatus()
{
    std::vector<IControl*> controls = this->GetAllControls();
    for (auto pControl : controls)
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(pControl != nullptr, L"pIControl为空",L"GDMPLab",L"2024-03-30");
        pControl->UpdateStatus();
    }
}

int StatusBarPanelImpl::GetStretch() const
{
    return m_stretch;
}

OwnerPtr<IControl> CreateControl(OwnerPtr<IControlDefinition> opDefinition)
{
    ControlDefinitionType definitionType = opDefinition->GetType();
    OwnerPtr<IControl> opControl = nullptr;
    switch (definitionType)
    {
    case gcmp::ControlDefinitionType::UnKnow:
    {
        DBG_WARN(L"无法处理的ControlDefinition类型",L"GDMPLab",L"2024-03-30");
        break;
    }
    case gcmp::ControlDefinitionType::CommandButton:
    {
        opControl = IControl::CreateButton(TransferOwnershipCast<ICommandButtonDefinition>(opDefinition));
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opControl, L"CreateQtButton返回空",L"GDMPLab",L"2024-03-30");
        break;
    }
    case gcmp::ControlDefinitionType::LineEdit:
    {
        opControl = IControl::CreateLineEdit(TransferOwnershipCast<ILineEditDefinition>(opDefinition));
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opControl, L"CreateQtLineEdit返回空",L"GDMPLab",L"2024-03-30");
        break;
    }
    case gcmp::ControlDefinitionType::CommandButtonMenu:
    {
        opControl = IControl::CreateCommandButtonMenu(TransferOwnershipCast<ICommandButtonMenuDefinition>(opDefinition));
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opControl, L"CreateQtCommandButtonMenu返回空",L"GDMPLab",L"2024-03-30");
        break;
    }
    case gcmp::ControlDefinitionType::Label:
    {
        opControl = IControl::CreateLabel(TransferOwnershipCast<ILabelDefinition>(opDefinition));
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opControl, L"CreateQtLabel返回空",L"GDMPLab",L"2024-03-30");
        break;
    }
    case gcmp::ControlDefinitionType::ProgressBar:
    {
        opControl = IControl::CreateProgressBar(TransferOwnershipCast<IProgressBarDefinition>(opDefinition));
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opControl, L"CreateQtProgressBar返回空",L"GDMPLab",L"2024-03-30");
        if (QWidget* pWidget = dynamic_cast<QWidget*>(opControl.get()))
        {
            pWidget->setFixedHeight(18);
            const IProgressBarDefinition* pDefine = dynamic_cast<const IProgressBarDefinition*>(opControl->GetControlDefinition());
            DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDefine, L"pDefine为空",L"GDMPLab",L"2024-03-30");
            pWidget->setFixedWidth(pDefine->GetWidth());
        }
        break;
    }
    case gcmp::ControlDefinitionType::ComboBox:
    {
        opControl = IControl::CreateComboBox(TransferOwnershipCast<IComboBoxDefinition>(opDefinition));
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opControl, L"CreateQtComboBox返回空",L"GDMPLab",L"2024-03-30");
        break;
    }
    default:
        DBG_WARN(L"未知的ControlDefinition类型",L"GDMPLab",L"2024-03-30");
        break;
    }
    return opControl;
}

OwnerPtr<IControl> CreateControlGroup(OwnerPtr<IControlDefinition> opDefinition, QWidget* pParentWidget)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pParentWidget, L"pParentWidget为空",L"GDMPLab",L"2024-03-30");
    UInt64 winId = pParentWidget->winId();

    ControlDefinitionType definitionType = opDefinition->GetType();    
    OwnerPtr<IControl> opControl = nullptr;
    switch (definitionType)
    {
    case gcmp::ControlDefinitionType::UnKnow:
    {
        DBG_WARN(L"无法处理的ControlDefinition类型",L"GDMPLab",L"2024-03-30");
        break;
    }
    case gcmp::ControlDefinitionType::CheckBoxGroup:
    {
        opControl = IControl::CreateCheckBoxGroup(TransferOwnershipCast<ICheckBoxGroupDefinition>(opDefinition), winId);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opControl, L"CreateQtButton返回空",L"GDMPLab",L"2024-03-30");
        break;
    }
    case gcmp::ControlDefinitionType::RadioButtonGroup:
    {
        opControl = IControl::CreateRadioButtonGroup(TransferOwnershipCast<IRadioButtonGroupDefinition>(opDefinition), winId);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opControl, L"CreateQtButton返回空",L"GDMPLab",L"2024-03-30");
        break;
    }
    default:
        DBG_WARN(L"未知的ControlDefinition类型",L"GDMPLab",L"2024-03-30");
        break;
    }
    return opControl;
}

template<typename ControlDefinitionType>
IControl* StatusBarPanelImpl::AddControl(OwnerPtr<ControlDefinitionType> pControlDefinition)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pControlDefinition, L"pControlDefinition是空指针",L"GDMPLab",L"2024-03-30");
    const std::wstring id = pControlDefinition->GetId();
    auto search = std::find_if(m_controls.begin(), m_controls.end(), FindControlPtrByIdPredicate<OwnerPtr<IControl>>(id));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(search == m_controls.end(), L"Panel上已经添加了控件：" + id,L"GDMPLab",L"2024-03-30");

    OwnerPtr<IControl> pControl = CreateControl(TransferOwnership(pControlDefinition));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pControl, L"CreateControl返回空",L"GDMPLab",L"2024-03-30");

    QWidget* pWidget = dynamic_cast<QWidget*>(pControl.get());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pWidget, L"pWidget为空",L"GDMPLab",L"2024-03-30");
    m_pHBoxLayout->addWidget(pWidget);
    IControl* res = pControl.get();
    m_controls.push_back(TransferOwnership(pControl));
    return res;
}

template<typename ControlDefinitionType>
IControl* StatusBarPanelImpl::InsertControl(const std::wstring& followingControlDefinitionId, OwnerPtr<ControlDefinitionType> pControlDefinition)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pControlDefinition, L"pControlDefinition是空指针",L"GDMPLab",L"2024-03-30");
    const std::wstring id = pControlDefinition->GetId();
    auto search = std::find_if(m_controls.begin(), m_controls.end(), FindControlPtrByIdPredicate<OwnerPtr<IControl>>(id));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(search == m_controls.end(), L"Panel上已经添加了控件：" + id,L"GDMPLab",L"2024-03-30");
    auto refSearch = std::find_if(m_controls.begin(), m_controls.end(), FindControlPtrByIdPredicate<OwnerPtr<IControl>>(followingControlDefinitionId));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(refSearch != m_controls.end(), L"Panel上没找到插入参考控件：" + followingControlDefinitionId,L"GDMPLab",L"2024-03-30");

    OwnerPtr<IControl> pControl = CreateControl(TransferOwnership(pControlDefinition));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pControl, L"CreateControl返回空",L"GDMPLab",L"2024-03-30");

    // 一个Control可能对应多个Qt Widget
    const int refQWidgetIndex = GetFirstQWidgetIndex(refSearch->get());

    QWidget* pWidget = dynamic_cast<QWidget*>(pControl.get());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pWidget, L"pWidget为空",L"GDMPLab",L"2024-03-30");
    m_pHBoxLayout->insertWidget(refQWidgetIndex, pWidget);

    IControl* res = pControl.get();
    m_controls.insert(refSearch, TransferOwnership(pControl));
    return res;
}

template<typename ControlGroupDefinitionType>
IControl* StatusBarPanelImpl::AddControlGroup(OwnerPtr<ControlGroupDefinitionType> pControlGroupDefinition)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pControlGroupDefinition, L"pControlDefinition是空指针",L"GDMPLab",L"2024-03-30");
    const std::wstring id = pControlGroupDefinition->GetId();
    auto search = std::find_if(m_controls.begin(), m_controls.end(), FindControlPtrByIdPredicate<OwnerPtr<IControl>>(id));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(search == m_controls.end(), L"Panel上已经添加了控件：" + id,L"GDMPLab",L"2024-03-30");

    OwnerPtr<IControl> pControlGroup = CreateControlGroup(TransferOwnership(pControlGroupDefinition), this);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pControlGroup, L"CreateControl返回空",L"GDMPLab",L"2024-03-30");

    if (QButtonGroup* pButtonGroup = dynamic_cast<QButtonGroup*>(pControlGroup.get()))
    {
        QList<QAbstractButton*> buttons = pButtonGroup->buttons();
        for (auto button : buttons)
        {
            DBG_WARN_AND_CONTINUE_UNLESS(button, L"button是空指针",L"GDMPLab",L"2024-03-30");
            m_pHBoxLayout->addWidget(button);
        }
    }
   
    IControl* res = pControlGroup.get();
    m_controls.push_back(TransferOwnership(pControlGroup));
    return res;
}

template<typename ControlGroupDefinitionType>
IControl* StatusBarPanelImpl::InsertControlGroup(const std::wstring& followingControlDefinitionId, OwnerPtr<ControlGroupDefinitionType> pControlGroupDefinition)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pControlGroupDefinition, L"pControlDefinition是空指针",L"GDMPLab",L"2024-03-30");
    const std::wstring id = pControlGroupDefinition->GetId();
    auto search = std::find_if(m_controls.begin(), m_controls.end(), FindControlPtrByIdPredicate<OwnerPtr<IControl>>(id));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(search == m_controls.end(), L"Panel上已经添加了控件：" + id,L"GDMPLab",L"2024-03-30");
    auto refSearch = std::find_if(m_controls.begin(), m_controls.end(), FindControlPtrByIdPredicate<OwnerPtr<IControl>>(followingControlDefinitionId));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(refSearch != m_controls.end(), L"Panel上没找到插入参考控件：" + followingControlDefinitionId,L"GDMPLab",L"2024-03-30");

    // 一个Control可能对应多个Qt Widget
    const int refQWidgetIndex = GetFirstQWidgetIndex(refSearch->get());

    OwnerPtr<IControl> pControlGroup = CreateControlGroup(TransferOwnership(pControlGroupDefinition), this);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pControlGroup, L"CreateControl返回空",L"GDMPLab",L"2024-03-30");
    int i = 0;
    if (QButtonGroup* pButtonGroup = dynamic_cast<QButtonGroup*>(pControlGroup.get()))
    {
        QList<QAbstractButton*> buttons = pButtonGroup->buttons();
        for (auto button : buttons)
        {
            m_pHBoxLayout->insertWidget(refQWidgetIndex + i, button);
            ++i;
        }
    }

    IControl* res = pControlGroup.get();
    m_controls.insert(refSearch, TransferOwnership(pControlGroup));
    return res;
}

int StatusBarPanelImpl::GetFirstQWidgetIndex(const IControl* pControl) const
{
    int index = -1;
    DBG_WARN_AND_RETURN_UNLESS(pControl, index, L"pControl是空指针",L"GDMPLab",L"2024-03-30");
    
    QWidget* pWidget = nullptr;
    if (const QButtonGroup* pButtonGroup = dynamic_cast<const QButtonGroup*>(pControl))
    {
        QList<QAbstractButton*> buttons = pButtonGroup->buttons();
        //QButtonGroup中为空时，需要找下一个define对应的控件，暂时处理为警告处理
        DBG_WARN_AND_RETURN_UNLESS(buttons.size() > 0, index, L"ButtonGroup中没有控件",L"GDMPLab",L"2024-03-30");
        pWidget = buttons[0];
    }
    else
    {
        pWidget = const_cast<QWidget*>(dynamic_cast<const QWidget*>(pControl));
    }

    DBG_WARN_AND_RETURN_UNLESS(pWidget, index, L"pWidget是空指针",L"GDMPLab",L"2024-03-30");

    return m_pHBoxLayout->indexOf(pWidget);
}

}   // end namespace gcmp
